package eu.liquify.ui {
	import flash.events.Event;
	import flash.events.FocusEvent;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.ui.Mouse;
	import flash.ui.MouseCursor;
	import no.doomsday.console.ConsoleUtil;
	public class Spinner extends TextBox implements ISimulatable, IHasBindValue {
		public var change:Function = NULL_FUNCTION;
		
		private var _min:Number = NaN;
		private var _max:Number = NaN;
		private var _step:Number = 0.1;
		private var _restrictStep:Boolean = false;
		private var v:Number = 0;
		
		private static var dragging:Boolean = false;
		
		private var over:Boolean = false;
		private var originalValue:Number;
		private var offset:Point = new Point();
		
		private var lastCursor:String = null;
		
		public function Spinner(options:Object = null) {
			super(options);
			
			//marginTop += 3;
			
			labelTxt.mouseEnabled = true;
			labelTxt.addEventListener(MouseEvent.ROLL_OVER, rollOver);
			labelTxt.addEventListener(MouseEvent.ROLL_OUT, rollOut);
			labelTxt.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
			addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheel);
			text = ""+v;
		}
		
		public function simulateEvent(e:Event):void {
			labelTxt.dispatchEvent(e);
		}
		
		public function get bindValue():Object { return value; }
		public function set bindValue(v:Object):void { value = Number(v); }
		public function get value():Number { return v; }
		public function set value(val:Number):void {
			updateValue(val, false);
		}
		
		public function get min():Number { return _min; }
		
		public function set min(value:Number):void {
			_min = value;
			updateValue();
		}
		
		public function get max():Number { return _max; }
		
		public function set max(value:Number):void {
			_max = value;
			updateValue();
		}
		
		public function get step():Number { return _step; }
		
		public function set step(value:Number):void {
			_step = value;
			updateValue();
		}
		
		public function get restrictStep():Boolean { return _restrictStep; }
		
		public function set restrictStep(value:Boolean):void {
			_restrictStep = value;
			updateValue();
		}
		
		private function mouseWheel(e:MouseEvent):void {
			//v += e.delta*step;
			updateValue(v+(e.delta > 0 ? step : -step));
			e.updateAfterEvent();
		}
		
		private function rollOver(e:MouseEvent):void {
			over = true;
			updateCursor();
		}
		
		private function updateCursor():void {
			if (over || dragging) {
				if (!dragging && !lastCursor) lastCursor = Mouse.cursor;
				Mouse.cursor = MouseCursor.HAND;
			} else if (lastCursor) {
				Mouse.cursor = lastCursor;
				lastCursor = null;
			}
		}
		
		private function rollOut(e:MouseEvent = null):void {
			over = false;
			updateCursor();
		}
		
		private function mouseDown(e:MouseEvent):void {
			offset.x = e.stageX;
			originalValue = v;
			stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
			dragging = true;
		}
		
		private function mouseMove(e:MouseEvent):void {
			updateValue(originalValue+(e.stageX-offset.x)*step);
			e.updateAfterEvent();
		}
		
		private function updateValue(newValue:Number = NaN, dispatch:Boolean = true):void {
			var oldValue:Number = v;
			if (!isNaN(newValue)) v = newValue;
			
			if (restrictStep) v = Math.round(v/step)*step;
			v = Math.round(v*1e12)/1e12;
			if (!isNaN(min) && v < min) v = min;
			else if (!isNaN(max) && v > max) v = max;
			if (oldValue != v || isNaN(newValue)) {
				text = ""+v;
				if (dispatch) {
					Utils.callDynamic(change, this);
					dispatchEvent(new ValueEvent(ValueEvent.VALUE_CHANGED, v));
				}
			}
		}
		
		override protected function updateChange():void {
			updateValue(Number(text));
		}
		
		private function mouseUp(e:MouseEvent):void {
			dragging = false;
			updateCursor();
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
			stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUp);
		}
		
	}
}